package com.ldj.base.impl;

import com.ldj.base.BaseEntityDao;
import com.ldj.base.Page;
import com.ldj.base.ReflectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hibernate.Criteria;
import org.hibernate.Query;
import org.hibernate.SessionFactory;
import org.hibernate.criterion.*;
import org.hibernate.internal.CriteriaImpl;
import org.hibernate.transform.ResultTransformer;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * All rights Reserved, Designed By 翼虎能源
 * Copyright:    Copyright(C) 2015-2015
 * Company       北京翼虎能源科技有限公司
 *
 * @author 吕东杰
 * @version 1.0
 * @date 2016/5/26 15:56
 * @Description Demo
 */
public class BaseEntityDaoImpl<Entity, PK extends Serializable> extends BaseDaoImpl<Entity, PK> implements BaseEntityDao<Entity, PK> {
    protected Log logger = LogFactory.getLog(BaseEntityDaoImpl.class);

    public BaseEntityDaoImpl() {
    }

    public Page<Entity> findPage(Page<Entity> page, Criteria c) {
        if(page.isAutoCount()) {
            long result = this.countCriteriaResult(c);
            page.setTotalCount(result);
        }

        this.setPageParameterToCriteria(c, page);
        List result1 = c.list();
        page.setResult(result1);
        return page;
    }

    public BaseEntityDaoImpl(SessionFactory sessionFactory, Class<Entity> entityClass) {
        super(sessionFactory, entityClass);
    }

    public Page<Entity> findAllByPage(Page<Entity> page) {
        return this.findPage(page, new Criterion[0]);
    }

    public Page<Entity> findPage(Page<Entity> page, String hql, Object... values) {
        Query q = this.createQuery(hql, values);
        if(page.isAutoCount()) {
            long result = this.countHqlResult(hql, values);
            page.setTotalCount(result);
        }

        this.setPageParameterToQuery(q, page);
        List result1 = q.list();
        page.setResult(result1);
        return page;
    }

    public Page<Entity> findPage(Page<Entity> page, String hql, Map<String, ?> values) {
        Query q = this.createQuery(hql, values);
        if(page.isAutoCount()) {
            long result = this.countHqlResult(hql, values);
            page.setTotalCount(result);
        }

        this.setPageParameterToQuery(q, page);
        List result1 = q.list();
        page.setResult(result1);
        return page;
    }

    public Page<Entity> findPage(Page<Entity> page, Criterion... criterions) {
        Criteria c = this.createCriteria(criterions);
        if(page.isAutoCount()) {
            long result = this.countCriteriaResult(c);
            page.setTotalCount(result);
        }

        this.setPageParameterToCriteria(c, page);
        List result1 = c.list();
        page.setResult(result1);
        return page;
    }

    protected Criteria setPageParameterToCriteria(Criteria c, Page<Entity> page) {
        c.setFirstResult(page.getFirst() - 1);
        c.setMaxResults(page.getPageSize());
        if(page.isOrderBySetted()) {
            String[] orderByArray = StringUtils.split(page.getOrderBy(), ',');
            String[] orderArray = StringUtils.split(page.getOrder(), ',');

            for(int i = 0; i < orderByArray.length; ++i) {
                if("asc".equals(orderArray[i])) {
                    c.addOrder(Order.asc(orderByArray[i]));
                } else {
                    c.addOrder(Order.desc(orderByArray[i]));
                }
            }
        }

        return c;
    }

    protected long countHqlResult(String hql, Map<String, ?> values) {
        String countHql = this.prepareCountHql(hql);

        try {
            Long e = (Long)this.findUniqueByHql(countHql, values);
            return e.longValue();
        } catch (Exception var5) {
            throw new RuntimeException("hql can\'t be auto count, hql is:" + countHql, var5);
        }
    }

    protected long countCriteriaResult(Criteria c) {
        CriteriaImpl impl = (CriteriaImpl)c;
        Projection projection = impl.getProjection();
        ResultTransformer transformer = impl.getResultTransformer();
        List orderEntries = null;

        try {
            orderEntries = (List) ReflectionUtils.getFieldValue(impl, "orderEntries");
            ReflectionUtils.setFieldValue(impl, "orderEntries", new ArrayList());
        } catch (Exception var11) {
            this.logger.error("不可能抛出的异常:" + var11.getMessage());
        }

        Long totalCountObject = (Long)c.setProjection(Projections.rowCount()).uniqueResult();
        long totalCount = totalCountObject != null?totalCountObject.longValue():0L;
        c.setProjection(projection);
        if(projection == null) {
            c.setResultTransformer(CriteriaSpecification.ROOT_ENTITY);
        }

        if(transformer != null) {
            c.setResultTransformer(transformer);
        }

        try {
            ReflectionUtils.setFieldValue(impl, "orderEntries", orderEntries);
        } catch (Exception var10) {
            this.logger.error("不可能抛出的异常:" + var10.getMessage());
        }

        return totalCount;
    }
}
